import React, {
  ReactNode,
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';
import { useTranslation } from 'react-i18next';
import {
  View,
  ScrollView,
  Platform,
  Pressable,
  TouchableOpacity,
  Button as RNButton,
  ActivityIndicator,
  Alert,
  StyleSheet,
  FlatList,
  Linking,
  ToastAndroid,
  Text,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Button, useAppTheme, TextInput, Icon } from 'tsun-smart-ui';
import WifiManager from 'react-native-wifi-reborn';
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
import useBleScan from '@/hooks/useBleScan';
import StringUtils from '@/utils/StringUtils';
import Animated, { FadeIn } from 'react-native-reanimated';
import { PeripheralInfo } from 'react-native-ble-manager';
import { ViewProps } from 'react-native-svg/lib/typescript/fabric/utils';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import AlertDialog from '@/components/AlertDialog';
import ArrayUtils from '@/utils/ArrayUtils';
import eventBus from '@/utils/eventBus';
import PermissionNotGrantedDialog from '@/components/PermissionNotGrantedDialog';
import { PERMISSIONS, request } from 'react-native-permissions';
import PermissionUtils from '@/utils/PermissionUtils';
import WiFiAnimation from '@/components/WiFiAnimation';

type NetworkSetupStep =
  | 'idle'
  | 'writing-ssid'
  | 'waiting-for-mesh-sn'
  | 'writing-mesh-sn'
  | 'done';

type BluetoothConnectionStatus = 'connecting' | 'connected' | 'failed';

// 进入页面，得到蓝牙名字，扫描周边设备，匹配名字得到MAC或者UUID，连接蓝牙设备，开始监听
const SetupDeviceNetwork = () => {
  const { t } = useTranslation();
  const route = useRoute<RouteProp<any>>();
  const navigation = useNavigation<NativeStackNavigationProp<any>>();
  const snCode = route.params?.snCode;
  const appTheme = useAppTheme();
  const [ssidName, setSsidName] = useState('');
  const [ssidPassword, setSsidPassword] = useState('');
  const [networkSetupStep, setNetworkSetupStep] =
    useState<NetworkSetupStep>('idle');
  const [receivedMeshSN, setReceivedMeshSN] = useState<string[]>([]);
  const [confirmedMeshSN, setConfirmedMeshSN] = useState<string[]>([]);
  const {
    bluetoothDialogShouldOpen,
    setBluetoothDialogShouldOpen,
    connectedPeripheral,
    write,
    startScan,
    peripherals,
    stopScan,
    permissionDialogShouldOpen,
    setPermissionDialogShouldOpen,
    connectToDevice,
    addListener,
  } = useBleScan();
  const communicateAlgorithm = useRef<number>(null);
  const [readyState, setReadyState] =
    useState<BluetoothConnectionStatus>('connecting');
  const isDeviceSupportMesh = useRef<boolean>(false);
  const timeoutRef = useRef<number>(null);
  const ssidRef = useRef<number>(null);
  const [receivedBle, setReceivedBle] = useState('');

  const syncSSID = useCallback(async () => {
    try {
      if (Platform.OS === 'ios') {
        await PermissionUtils.checkPermission(
          PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
        );
      }
      const ssid = await WifiManager.getCurrentWifiSSID();
      setSsidName(ssid);
    } catch (e) {}
  }, []);

  useEffect(() => {
    syncSSID();
    startScanAndAddTimeOut();
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
      if (ssidRef.current) {
        clearTimeout(ssidRef.current);
      }
    };
  }, []);

  useEffect(() => {
    const deviceName = snCode;
    if (deviceName) {
      const device = peripherals.find((item) => {
        const deviceDisplayName =
          item.name ?? item.advertising.localName ?? item.id;
        return deviceDisplayName === deviceName;
      });
      if (device) {
        console.log('找到设备', device);
        connectDeviceAndSetupListener(device.id);
      }
    }
  }, [peripherals]);

  const connectDeviceAndSetupListener = useCallback(
    (deviceId: string) => {
      stopScan().then(() => {
        console.log('开始连接设备');
        if (connectedPeripheral.current) {
          return Promise.reject('已经连接成功了，不需要重复连接了');
        }
        connectToDevice(deviceId)
          .then((peripheralInfo) => {
            addListener((receivedValue) => {
              let receivedContent = StringUtils.decryptContentForTSUNBle(
                receivedValue,
                communicateAlgorithm.current ?? 0
              );
              console.log(
                `收到来自设备的通知：${JSON.stringify(
                  receivedValue
                )}，解析后的数据：${JSON.stringify(receivedContent)}`
              );
              setReceivedBle(
                `收到来自设备的数据：${receivedValue}，解析后：${JSON.stringify(
                  receivedContent
                )}`
              );
              /// 协商算法
              const algorithmRegex = /AT\+KEY=(\d+)\r\n$/;
              /// 进入配网模式
              const workingMode = new RegExp('AT\\+WORKMODE=(\\d+),OK\\r\\n');
              /// 配网结果
              const wifiSetupSuccessRegex = /AT\+WIFI=OK,([\d+])\r\n$/;
              /// 配网失败
              const wifiSetupFailedRegex = /AT\+WIFI=([^\r\n]+)\r\n$/;
              /// 扫描到新mesh设备
              const meshSerialNumberRegex = /AT\+MESHSN=([\d\w]+)\r\n/;
              const meshSetupComplete = /^AT\+MESH=OK\r\n$/;

              const algorithmMatchResult =
                receivedContent.match(algorithmRegex);
              if (algorithmMatchResult) {
                console.log('算法匹配成功，内容是：', algorithmMatchResult);
                const algorithm = parseInt(algorithmMatchResult[1]);
                communicateAlgorithm.current = algorithm;
                const setWorkingMode = 'AT+WORKMODE=1\r\n';
                write(
                  StringUtils.encryptContentForTSUNBle(
                    setWorkingMode,
                    algorithm
                  )
                );
                return;
              }

              const workingModeMatchResult = receivedContent.match(workingMode);
              if (workingModeMatchResult) {
                console.log(
                  '工作模式匹配成功，内容是：',
                  workingModeMatchResult
                );
                const meshSupported = workingModeMatchResult[1];
                const isMeshSupported = meshSupported === '1';
                isDeviceSupportMesh.current = isMeshSupported;
                setReadyState('connected');
                return;
              }

              const wifiSetupSuccessMatchResult = receivedContent.match(
                wifiSetupSuccessRegex
              );
              if (wifiSetupSuccessMatchResult) {
                const wifiSetupResult = wifiSetupSuccessMatchResult[1];
                /// 配网后的mesh，已废弃
                // const supportMesh = wifiSetupResult === '1';
                // console.log('配网成功，设备支持mesh：', supportMesh);
                if (isDeviceSupportMesh.current) {
                  setNetworkSetupStep('waiting-for-mesh-sn');
                } else {
                  setNetworkSetupStep('done');
                }
                return;
              }

              const wifiSetupFailedMatchResult =
                receivedContent.match(wifiSetupFailedRegex);
              if (wifiSetupFailedMatchResult) {
                const wifiSetupFailedResult = wifiSetupFailedMatchResult[1];
                setNetworkSetupStep('idle');
                console.log('配网失败，失败原因：', receivedContent);
                return;
              }

              const meshSerialNumberMatchResult = receivedContent.match(
                meshSerialNumberRegex
              );
              if (meshSerialNumberMatchResult) {
                const meshSerialNumber = meshSerialNumberMatchResult[1];
                setReceivedMeshSN((prev) => {
                  if (prev.includes(meshSerialNumber)) {
                    return prev;
                  }
                  return [...prev, meshSerialNumber];
                });
                return;
              }

              if (meshSetupComplete.test(receivedContent)) {
                navigation.popToTop();
                return;
              }
            }).then(() => {
              negotiateAlgorithmToUse(peripheralInfo);
            });
          })
          .catch((reason) => {
            setReadyState('failed');
          });
      });
    },
    [connectedPeripheral]
  );

  const negotiateAlgorithmToUse = useCallback(
    (peripheralInfo: PeripheralInfo) => {
      const algorithm = Math.floor(Math.random() * 10) + 1;
      // const algorithm = 0;
      const content = `AT+KEY=${algorithm}\r\n`;
      write(StringUtils.encryptContentForTSUNBle(content));
    },
    [connectedPeripheral]
  );

  const startScanAndAddTimeOut = useCallback(() => {
    setReadyState('connecting');
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
    timeoutRef.current = setTimeout(() => {
      if (!connectedPeripheral.current) {
        setReadyState('failed');
      }
    }, 21000);
    startScan([], 20, false, {});
  }, []);

  const onNextStep = useCallback(() => {
    if (readyState !== 'connected') {
      startScanAndAddTimeOut();
      return;
    }
    if (networkSetupStep === 'idle') {
      if (connectedPeripheral) {
        setNetworkSetupStep('writing-ssid');
        const content = `AT+WIFI=${ssidName},${ssidPassword},1\r\n`;
        /// MARK: 硬件要求，进入workmode状态后，必须等待5秒钟才能下发配网指令
        ssidRef.current = setTimeout(() => {
          write(
            StringUtils.encryptContentForTSUNBle(
              content,
              communicateAlgorithm.current ?? 0
            )
          )
            .then((value) => {
              console.log('写入成功', value);
            })
            .catch((reason) => {
              console.log('写入失败', reason);
              setNetworkSetupStep('idle');
            });
        }, 5000);
      }
    } else if (networkSetupStep === 'writing-ssid') {
      // setNetworkSetupStep('waiting-for-mesh-sn');
    } else if (networkSetupStep === 'waiting-for-mesh-sn') {
      // setNetworkSetupStep('writing-mesh-sn');
      if (ArrayUtils.isNotEmpty(confirmedMeshSN)) {
        setNetworkSetupStep('waiting-for-mesh-sn');
        const content = `AT+MESH=${
          confirmedMeshSN.length
        },${confirmedMeshSN.join(',')}\r\n`;
        write(
          StringUtils.encryptContentForTSUNBle(
            content,
            communicateAlgorithm.current ?? 0
          )
        )
          .then(() => {
            setNetworkSetupStep('done');
          })
          .catch((reason) => {
            setNetworkSetupStep('waiting-for-mesh-sn');
          });
      } else {
        navigation.popToTop();
      }
    } else if (networkSetupStep === 'writing-mesh-sn') {
      // setNetworkSetupStep('done');
    } else {
      eventBus.emit('DEVICE_CHANGE');
      navigation.popToTop();
    }
  }, [
    ssidName,
    ssidPassword,
    networkSetupStep,
    connectedPeripheral,
    confirmedMeshSN,
  ]);

  const renderIdle = useCallback(() => {
    return (
      <PageContainer onNextStep={onNextStep} readyState={readyState}>
        <ScrollView className="flex-1" contentContainerClassName="px-4 pt-4">
          <Text
            style={{
              color: appTheme.colors?.neutral?.secondaryTitle,
            }}
            className="text-[15px] text-text2"
          >
            {t('sys.app.wifi.name', { defaultValue: 'Wi-Fi名称' })}
          </Text>
          <TextInput
            className="mt-2 text-[18px]"
            value={ssidName}
            onChangeText={setSsidName}
            placeholder={t('client.inputResourceIdsTip', {
              defaultValue: '请输入',
            })}
            right={
              <Button
                title={t('sys.app.use.current.wifi', {
                  defaultValue: '使用当前Wi-Fi',
                })}
                variant="text"
                onPress={syncSSID}
              />
            }
          />
          <Text className="text-[15px] text-text2 mt-4">
            {t('sys.app.wifi.psw', { defaultValue: 'Wi-Fi密码' })}
          </Text>
          <TextInput
            className="mt-2 mb-4"
            value={ssidPassword}
            onChangeText={setSsidPassword}
            placeholder={t('client.inputResourceIdsTip', {
              defaultValue: '请输入',
            })}
          />
          <Text className="text-text1 text-[14px]">
            {t('sys.app.prerequisite', { defaultValue: '前提条件' })}
          </Text>
          <Text className="text-text2 text-[12px] mt-2">
            1.{' '}
            {t('sys.app.wifi.not.support.5g', {
              defaultValue: '不支持5G网络。',
            })}
          </Text>
          <Text className="text-text2 text-[12px] mt-1">
            2.{' '}
            {t('sys.app.pls.confirm.bluetooth.on', {
              defaultValue: '请确认蓝牙已开启。',
            })}
          </Text>
          {/*<Text>DEBUG: {receivedBle}</Text>*/}
        </ScrollView>
        <AlertDialog
          visible={bluetoothDialogShouldOpen}
          onDismiss={() => setBluetoothDialogShouldOpen(false)}
          title={t('sys.app.open.ble')}
          subtitle={t('sys.app.open.ble.detail')}
          buttons={[
            {
              title: t('user.logOutCancel'),
              onPress: () => {
                /// 蓝牙没开启，又点了取消
              },
            },
            {
              title: t('common.confirmButtonText'),
              highlighted: true,
              onPress: () => {
                /// TODO: 这里按理说需要引导用户打开控制中心的蓝牙开关，但是产品和UI没有提供文案和交互，所以先跳转到系统设置
                Linking.openSettings();
              },
            },
          ]}
        />
        <PermissionNotGrantedDialog
          visible={permissionDialogShouldOpen}
          onDismiss={() => setPermissionDialogShouldOpen(false)}
        />
      </PageContainer>
    );
  }, [
    ssidName,
    ssidPassword,
    readyState,
    permissionDialogShouldOpen,
    receivedBle,
  ]);

  const renderNetworkSetup = useCallback(() => {
    return (
      <View className="flex-1 items-center gap-3 px-10 mt-32">
        <WiFiAnimation style={{ width: 200, height: 200 }} />
        <FakeProgressBar visible done={networkSetupStep === 'done'} />
        <WritingDataStep
          title={t('sys.app.writing.ssid', {
            defaultValue: '正在写入Wi-Fi信息',
          })}
          succeed={false}
        />
      </View>
    );
  }, [ssidName, ssidPassword]);

  const renderWaitingForWifiMesh = useCallback(() => {
    return (
      <PageContainer onNextStep={onNextStep}>
        <FlatList
          className="flex-1"
          contentContainerClassName="px-4"
          data={receivedMeshSN}
          ListHeaderComponent={WaitingForMeshStateHeader}
          renderItem={({ item, index }: { item: any; index: number }) => {
            const isSelected = confirmedMeshSN.includes(item);
            return (
              <FoundMeshDeviceItem
                name={item}
                index={index}
                total={receivedMeshSN.length}
                onPress={() => {
                  setConfirmedMeshSN((prev) => {
                    if (prev.includes(item)) {
                      return prev.filter((i) => i !== item);
                    }
                    return [...prev, item];
                  });
                }}
                selected={isSelected}
              />
            );
          }}
          ListFooterComponent={WaitingForMeshStateFooter}
          keyExtractor={(item) => item}
        />
      </PageContainer>
    );
  }, [receivedMeshSN, confirmedMeshSN, networkSetupStep]);

  const renderWritingMeshSn = useCallback(() => {
    return (
      <View className="flex-1 items-center justify-center gap-3  px-10">
        <WiFiAnimation style={{ width: 200, height: 200 }} />
        <FakeProgressBar visible done={networkSetupStep === 'done'} />
        <WritingDataStep title={'SN序列号'} succeed={false} />
      </View>
    );
  }, []);

  const renderDone = useCallback(() => {
    return (
      <PageContainer onNextStep={onNextStep}>
        <View className="items-center gap-4 px-2 mb-3 flex-1 mt-32">
          <Icon
            name="check-circle"
            size={82}
            color={appTheme.colors?.success?.primary}
          />
          <Text className="text-[18px] text-text1 font-semibold">
            {t('sys.app.network.setup.succees')}
          </Text>
        </View>
      </PageContainer>
    );
  }, [networkSetupStep, readyState]);

  switch (networkSetupStep) {
    case 'idle':
      return renderIdle();
    case 'writing-ssid':
      return renderNetworkSetup();
    case 'waiting-for-mesh-sn':
      return renderWaitingForWifiMesh();
    case 'writing-mesh-sn':
      return renderWritingMeshSn();
    default:
      return renderDone();
  }
};

export default React.memo(SetupDeviceNetwork);

const PageContainer = React.memo(
  (
    props: ViewProps & {
      onNextStep: () => void;
      readyState?: BluetoothConnectionStatus;
    }
  ) => {
    const { t } = useTranslation();
    const resolvedReadyState = props.readyState ?? 'connected';
    const loading = resolvedReadyState === 'connecting';
    let confirmButtonTitle = t('common.confirmButtonText', {
      defaultValue: '确认',
    });
    if (resolvedReadyState === 'connecting') {
      confirmButtonTitle = t('sys.app.bluetooth.connection', {
        defaultValue: '连接蓝牙中',
      });
    } else if (resolvedReadyState === 'failed') {
      confirmButtonTitle = t('sys.app.ble.connection.failed', {
        defaultValue: '蓝牙连接失败',
      });
      confirmButtonTitle += ` ${t('common.retry', { defaultValue: '重试' })}`;
    }
    return (
      <View className="flex-1">
        {props.children}
        <SafeAreaView
          edges={['left', 'right', 'bottom']}
          className="px-4 py-2 shadow-sm bg-text6"
          // style={{ backgroundColor: appTheme.colors?.neutral?.white }}
        >
          <Button
            title={confirmButtonTitle}
            onPress={props.onNextStep}
            loading={loading}
          />
        </SafeAreaView>
      </View>
    );
  }
);

const WaitingForMeshStateHeader = React.memo(() => {
  const appTheme = useAppTheme();
  const { t } = useTranslation();
  return (
    <View className="items-center gap-4 px-2 pt-8 mb-3">
      <Icon
        name="check-circle"
        size={64}
        color={appTheme.colors?.success?.primary}
      />
      <Text className="text-[15px] text-text1 font-medium">
        {t('sys.app.network.setup.succees')}
      </Text>
      <Text className="text-text1 text-[15px]">
        <Icon
          name="warning"
          size={18}
          color={appTheme.colors?.warning?.primary}
        />
        {t('sys.app.pls.confirm.these.device')}
      </Text>
      <Text className="self-stretch text-text2 text-[14px]">
        {t('sys.app.mesh.devices')}
      </Text>
    </View>
  );
});

const WaitingForMeshStateFooter = React.memo(() => {
  const appTheme = useAppTheme();
  return (
    <View className="mb-9 items-center py-3">
      <ActivityIndicator color={appTheme.colors?.brand?.onPrimary} />
    </View>
  );
});

const FoundMeshDeviceItem = React.memo(
  (props: {
    name: string;
    index: number;
    total: number;
    selected: boolean;
    onPress: () => void;
  }) => {
    const appTheme = useAppTheme();
    const checkButtonColor = props.selected
      ? appTheme.colors?.brand?.primary
      : appTheme.colors?.neutral?.secondaryTitle;
    const checkButtonIconName = props.selected ? 'check-circle' : 'circle';

    const isFirst = props.index === 0;
    const isLast = props.index === props.total - 1;
    let roundedStyleText = '';
    if (isFirst) {
      roundedStyleText += ' rounded-t-[8px] ';
    }
    if (isLast) {
      roundedStyleText += 'rounded-b-[8px]';
    }

    return (
      <TouchableOpacity
        className={`flex-row items-center px-3 py-3 gap-2 bg-text6 ${roundedStyleText}`}
        onPress={props.onPress}
      >
        <Icon
          name="equipment"
          color={appTheme.colors?.neutral?.secondaryTitle}
          size={22}
        />
        <Text>{props.name}</Text>
        <View className="grow" />
        <Icon name={checkButtonIconName} size={18} color={checkButtonColor} />
      </TouchableOpacity>
    );
  }
);

interface FakeProgressBarProps {
  visible: boolean;
  done?: boolean;
  height?: number;
  color?: string;
}

const MAX_PROGRESS = 0.9; // 最大自动进度
const SPEED = 0.01; // 每次增加的进度
const INTERVAL = 100; // ms

const FakeProgressBar: React.FC<FakeProgressBarProps> = ({
  visible,
  done,
  color = '#45C673',
}) => {
  const [progress, setProgress] = useState(0);
  const intervalRef = useRef<number>(null);

  useEffect(() => {
    if (!visible) {
      setProgress(0);
      return;
    }
    if (done) {
      setProgress(1);
      return;
    }
    if (progress >= MAX_PROGRESS) return;

    intervalRef.current = setInterval(() => {
      setProgress((prev) => {
        if (done) return 1;
        if (prev < MAX_PROGRESS) {
          return Math.min(prev + SPEED, MAX_PROGRESS);
        }
        return prev;
      });
    }, INTERVAL);

    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current);
    };
  }, [visible, done]);

  useEffect(() => {
    if (done) setProgress(1);
  }, [done]);

  if (!visible) return null;

  return (
    <View className="h-[6px] rounded-full bg-line1 w-52">
      <Animated.View
        style={[
          {
            height: 6,
            borderRadius: 3,
          },
          {
            backgroundColor: color,
            width: `${progress * 100}%`,
          },
        ]}
      />
    </View>
  );
};

type WritingDataStepProps = {
  title: string;
  succeed: boolean;
};

const WritingDataStep: React.FC<WritingDataStepProps> = React.memo((props) => {
  const appTheme = useAppTheme();
  let indicator: ReactNode = null;
  let textColor: string | undefined;
  if (props.succeed) {
    indicator = <Icon name="check" size={18} />;
    textColor = appTheme.colors?.neutral?.primary;
  } else {
    indicator = (
      <ActivityIndicator
        size={'small'}
        color={appTheme.colors?.brand?.primary}
      />
    );
    textColor = appTheme.colors?.neutral?.secondaryTitle;
  }
  return (
    <Animated.View className="flex-row items-center gap-2" entering={FadeIn}>
      {indicator}
      <Text style={{ fontSize: 15, color: textColor }}>{props.title}</Text>
    </Animated.View>
  );
});
